﻿//Copyright (C) <2013>  <jonathan cleeve norton> All Rights Reserved 
//Contact jon.norton@fin-plus.co.uk website <http://www.fin-plus.co.uk/>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Controls.Primitives;
using System.Reflection;
using FinPlusCommon;
using log = Logger.Logger;
using u = FinPlusUtility.Utility;

namespace FinPlusWPFControls
{
    public partial class FinPlusFilterbar : FinPlusControl
    {
        public override string Id { get; set; }
        public override string[] States { get { return new string[] { "Height", "Width", "Left", "Top" , "FilteredOut"}; } }
        public override string[] TestStates { get { return new string[] { "IsValid", "ChildrenCount","FilteredOut", "ItemName"}; } }
        public override IFinPlusFunctions Model { get { return null; } }
        public override string ModelTest { get { return null; } }
        public override bool IsValid { get; set; }

        public IList<object> FilterOut{ get{ return _filterOut;} set { _filterOut = value;} }
        public string FilteredOut {get { return string.Format(String.Join(",", FilterOut.ToArray())).ToString(); } set { _filterOut = value.Split(',').ToList<object>(); Refresh(); } }
        public int ChildrenCount { get { return filterBar.Children.Count; } }
        public new string Name { get { return _name; } }

        private readonly FinPlusFuncStack _cmdStack;
        private IList<object> _filterOut;
        private Action _filterCallback;
        private bool _filterClearing;
        private readonly string _name;

        //construct
        public FinPlusFilterbar(string itemName)
        {
            InitializeComponent();
            _name = itemName;
            _filterOut = new List<object>();
            _cmdStack = new FinPlusFuncStack();
            IsValid = true;
        }

        //common control interface
        public override void Dock(object control, string dock)
        {
            try
            {
                filterBar.Children.Add((UserControl)control);
            }
            catch (Exception e)
            {
                IsValid = log.Log(Logger.Level.Warning, e.Message, e);
                filterBar.Children.Add(new FinPlusErrorDisplay(e));
            }
        }

        public override void Initialise()
        {

        }

        public override void CommandRouter(IFinPlusFunction func)
        {
            try
            {
                CaptureCommand(func);

                switch ((Commands)Enum.Parse(typeof(Commands), func.Name, true))
                {
                    case Commands.Filter: _cmdStack.Last = func; Filter(func); break;
                    case Commands.FilterUndo: Filter(_cmdStack.Last, true); break;
                    case Commands.FilterRedo: Filter(_cmdStack.Next); break;
                    case Commands.FilterClear: FilterClear(); break;
                    default: throw new Exception(string.Format("event not recognised {0}", func.Name));
                }
            }
            catch (Exception e)
            {
                IsValid = log.Log(Logger.Level.Warning, e.Message, e);
            }
        }

        public override void Dispose()
        {
            try
            {
                throw new NotImplementedException();
            }
            catch (Exception e)
            {
                log.Log(Logger.Level.Warning, e.Message, e);
            }
        }

        //public
        public void AddViewSource(FuncDynamics funcsDynamic, Action filterCallback)
        {
            try
            {
                _filterCallback = filterCallback;
                var values = new SortedSet<object>();
                object vals = string.Empty;

                foreach (var func in funcsDynamic)
                    if (func.TryGetObject(_name, out vals) && !values.Contains(vals.ToString()))
                        foreach (var val in vals.ToString().Split(','))
                            values.Add(val);

                foreach (var value in values)
                    AddButton(value);
            }
            catch (Exception e)
            {
                log.Log(Logger.Level.Error, Id, Config, e.Message, e);
                filterBar.Children.Add(new FinPlusErrorDisplay(e));
            }
        }

        //private
        private void Refresh()
        {
            foreach (var b in filterBar.Children.OfType<ToggleButton>())
                if (_filterOut.Where(f => b.Content.Equals(f.ToString())).Count() > 0)
                    b.IsChecked = false;

            _filterCallback();
        }

        private bool Filter(IFinPlusFunction func, bool undo = false)
        {
            if (func != null)
            {
                var isChecked = (bool)func.Value("IsChecked");
                if (undo) isChecked = !isChecked;

                var b = GetButton(func["Content"].ToString());
                if (b != null && b.IsChecked != isChecked)
                    b.IsChecked = isChecked;

                var value = func.Value("Content");

                if (isChecked && FilterOut.Contains(value))
                    FilterOut.Remove(value);
                else if (!isChecked && !FilterOut.Contains(value))
                    FilterOut.Add(value);
                else
                    return true;

                _filterCallback();
            }
            return false;
        }

        private bool FilterClear()
        {
            _filterClearing = true;

            if (FilterOut.Count > 0)
            {
                FilterOut.Clear();
                foreach (var control in filterBar.Children.OfType<ToggleButton>())
                    control.IsChecked = true;
            }
            else
            {
                FilterOut.Clear();
                foreach (var control in filterBar.Children.OfType<ToggleButton>())
                {
                    control.IsChecked = false;
                    FilterOut.Add(control.Content);
                }
            }

            _filterCallback();
            _filterClearing = false;
            return true;
        }

        private ToggleButton GetButton(string tag)
        {
            var l = filterBar.Children.OfType<ToggleButton>().Where(b => b.Tag.Equals(tag)).ToList();
            return l.Count() < 1 ? null : l[0];
        }

        private void AddButton(object value)
        {
            var b = new ToggleButton() 
            { 
                MinWidth = 20,
                Content = value.ToString(), 
                Tag = value, 
                IsChecked = IsEnabled = true,
                Style = (Style)FindResource("FilterToggleButtonStyle"),
                Name = u.Replace(value.ToString(), ".| |/|-", "_"), 
            };
            b.Click += Filter_Click;
            filterBar.Children.Add(b);
        }

        //cmds
        private new enum Commands { Filter, FilterClear, FilterRedo, FilterUndo }

        //events
        private void Filter_Click(object sender, RoutedEventArgs a)
        {
            if (_filterClearing) return;
            var b = (ToggleButton)sender;
            var func = new Function(Commands.Filter.ToString(), Id, User, -1, _name);
            func["Tag", User] = b.Tag;
            func["Content", User] = b.Content;
            func["IsChecked", User] = b.IsChecked;
            CommandRouter(func);
        }
        private void FilterRedo_OnClick(object sender, RoutedEventArgs a) { CommandRouter(new Function(Commands.FilterRedo.ToString(), Id, User)); }
        private void FilterUndo_OnClick(object sender, RoutedEventArgs a) { CommandRouter(new Function(Commands.FilterUndo.ToString(), Id, User)); }
        private void FilterClear_OnClick(object sender, RoutedEventArgs a) { CommandRouter(new Function(Commands.FilterClear.ToString(), Id, User)); }
    }
}
